﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DependencyParse.Library;

namespace DependencyParse
{
    using FxLib.Algorithms;
    using System.Xml;
    using System.IO;
    using FxLib.Controls;

    public partial class UnityDependencyCreateForm : Form
    {
        BindingManagerBase mBindingManager;

        public UnityDependencyCreateForm()
        {
            InitializeComponent();

            mBindingManager = mRelationGrid.BindingContext[Relation];
        }



        SortedBindingList<RelationEntity> Relation
        {
            get
            {
                if (mRelationGrid.DataSource == null)
                    mRelationGrid.DataSource = new SortedBindingList<RelationEntity>();
                return (SortedBindingList<RelationEntity>)mRelationGrid.DataSource;
            }
        }

        class ImpEntity
        {
            public string ClassName { get; set; }
            public string Interfaces { get; set; }
            public ClassEntity ClassEntityObj { get; set; }
        }

        class IEntity
        {
            public string InterfaceName { get; set; }
            public InterfaceEntity InterfaceEntityObj { get; set; }
        }

        class RelationEntity
        {
            public string ClassName { get; set; }
            public string InterfaceName { get; set; }
            public ClassEntity ClassObj { get; set; }
            public InterfaceEntity InterfaceObj { get; set; }
        }

        private void mParseButton_Click(object sender, EventArgs e)
        {

            List<InterfaceEntity> its = new List<InterfaceEntity>();
            AssemblyHelper.Load(mAssemblyPath.Text.Trim()).Classes.ForEach(
                n => its.AddRange(n.ReferencedDependencyInterfaces)
                );

            var uniqueIts = its.SafeUniqueItems(n => n.Add(m => m.FullName));

            mImpClassGrid.DataSource = GenerateTempBinding(AssemblyHelper.Load(mAssemblyPath.Text.Trim()).Classes
                .FindAll(n => n.ImplementedInterfaces.SafeExists(m=>uniqueIts.SafeExists(l=>l.FullName == m.FullName))).ConvertAll(n =>
                new ImpEntity
                {
                    ClassName = n.Name,
                    Interfaces = GetInterfaceNames(n),
                    ClassEntityObj = n,
                }));


            mInterfaceGrid.DataSource = GenerateTempBinding(uniqueIts.SafeConvetAll(n => new IEntity
            {
                InterfaceName = n.Name,
                InterfaceEntityObj = n
            }));

        }

        private string GetInterfaceNames(ClassEntity classEntity)
        {
            return string.Join(", ", classEntity.ImplementedInterfaces.ConvertAll(n => n.FullName).ToArray());
        }

        private SortedBindingList<T> GenerateTempBinding<T>(List<T> list)
        {
            return new SortedBindingList<T>(list);
        }

        private ClassEntity SelectedClassEntity
        {
            get
            {
                if (mImpClassGrid.DataSource == null)
                    return null;

                var b = mImpClassGrid.BindingContext[mImpClassGrid.DataSource];
                if (b.Current != null)
                    return ((ImpEntity)b.Current).ClassEntityObj;
                else
                    return null;
            }
        }

        private InterfaceEntity SelectedInterfaceEntity
        {
            get
            {
                if (mInterfaceGrid.DataSource == null)
                    return null;

                var b = mInterfaceGrid.BindingContext[mInterfaceGrid.DataSource];
                if (b.Current != null)
                    return ((IEntity)b.Current).InterfaceEntityObj;
                else
                    return null;
            }
        }

        private void mAddButton_Click(object sender, EventArgs e)
        {
            if (SelectedClassEntity == null)
            {
                MessageBox.Show("Please select class entity first");
                return;
            }

            if (SelectedInterfaceEntity == null)
            {
                MessageBox.Show("Please select interface entity first");
                return;
            }

            if (!SelectedClassEntity.ImplementedInterfaces.Exists
                (i => i.FullName == SelectedInterfaceEntity.FullName))
            {
                MessageBox.Show("The selected class and interface are not matched");
                return;
            }

            if (Relation.SafeExists(n => n.ClassObj.FullName == SelectedClassEntity.FullName
                && n.InterfaceObj.FullName == SelectedInterfaceEntity.FullName))
            {
                MessageBox.Show("Relation has been existed");
                return;
            }

            Relation.Add(new RelationEntity
            {
                ClassName = SelectedClassEntity.Name,
                InterfaceName = SelectedInterfaceEntity.Name,
                ClassObj = SelectedClassEntity,
                InterfaceObj = SelectedInterfaceEntity,
            });


        }

        private void mRemoveButton_Click(object sender, EventArgs e)
        {
            if (mBindingManager.Position != -1)
            {
                Relation.RemoveAt(mBindingManager.Position);
            }
        }

        private void mGenButton_Click(object sender, EventArgs e)
        {
            mOutputText.Text = GenerateUnityConfiguration(Relation, mContainerName.Text);

        }

        private string GenerateUnityConfiguration(IList<RelationEntity> relationEntities, string containerName)
        {
            XmlDocument doc = new XmlDocument();

            var docRoot = doc.CreateElement("root");
            doc.AppendChild(docRoot);

            var configSections = doc.CreateElement("configSections");
            docRoot.AppendChild(configSections);

            //sectionName
            var section = doc.CreateElement("section");
            var attName = doc.CreateAttribute("name");
            attName.Value = "unity";

            var attT = doc.CreateAttribute("type");
            attT.Value = "Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration";

            section.Attributes.Append(attName);
            section.Attributes.Append(attT);

            configSections.AppendChild(section);





            var root = doc.CreateElement("unity");
            docRoot.AppendChild(root);



            //containers
            var containers = doc.CreateElement("containers");
            root.AppendChild(containers);

            //container
            var container = doc.CreateElement("container");
            var att = doc.CreateAttribute("name");
            if (string.IsNullOrEmpty(containerName))
                containerName = "container1";
            att.Value = containerName;
            container.Attributes.Append(att);
            containers.AppendChild(container);

            //types
            var types = doc.CreateElement("types");
            container.AppendChild(types);

            foreach (var relation in relationEntities)
            {
                var type = doc.CreateElement("type");
                var attType = doc.CreateAttribute("type");
                attType.Value = relation.InterfaceObj.FullName + ", " + relation.InterfaceObj.AssemblyName;

                var attMapTo = doc.CreateAttribute("mapTo");
                attMapTo.Value = relation.ClassObj.FullName + ", " + relation.ClassObj.AssemblyName;
                type.Attributes.Append(attType);
                type.Attributes.Append(attMapTo);

                types.AppendChild(type);
            }

            using (MemoryStream mem = new MemoryStream())
            {
                using (XmlTextWriter wt = new XmlTextWriter(mem, Encoding.Default))
                {
                    wt.Indentation = 4;
                    wt.Formatting = Formatting.Indented;

                    doc.Save(wt);
                    wt.Flush();

                    mem.Position = 0;

                    using (StreamReader sr = new StreamReader(mem))
                    {
                        return sr.ReadToEnd();
                    }
                }

                
            }
        }

        private void mSelectPathButton_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog folderBowser = new FolderBrowserDialog();
            if (folderBowser.ShowDialog() == DialogResult.OK)
            {
                mAssemblyPath.Text = folderBowser.SelectedPath;
            }
        }
    }


}
